//
//  RDeliverySDK.h
//  RDeliverySDK
//
//  Created by selmerzhang on 2021/7/27.
//  Copyright © 2021 Tencent. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "RDConfigInfo.h"
#import "RDConfigInfoListener.h"
#import "RDConfigEventListener.h"
#import "RDeliverySDKSettings.h"

@class RDeliverySDKSettings;


NS_ASSUME_NONNULL_BEGIN

@interface RDeliverySDK : NSObject

/// 设置参数
@property (nonatomic, strong, readonly) RDeliverySDKSettings *settings;

#pragma mark - Init

/// 使用 @code + (instancetype)createSDKWithSettings: @endcode 方法进行初始化
- (instancetype)init NS_UNAVAILABLE;

/// 使用 @code + (instancetype)createSDKWithSettings: @endcode 方法进行初始化
- (instancetype)new NS_UNAVAILABLE;

/// 根据RDeliverySDKSettings初始化创建SDK
/// @param settings SDK参数设置
+ (instancetype)createSDKWithSettings:(RDeliverySDKSettings *)settings;

#pragma mark - Config Getter

/// 获取一个完整的配置信息
/// @param key 配置的key值
- (nullable RDConfigInfo *)configInfoWithKey:(NSString *)key;

/// 获取BOOL类型值
/// @param key 配置的key值
- (BOOL)boolValueWithKey:(NSString *)key;

/// 获取NSInteger类型值
/// @param key 配置的key值
- (NSInteger)intValueWithKey:(NSString *)key;

/// 获取NSUInteger类型值
/// @param key 配置的key值
- (NSUInteger)uintValueWithKey:(NSString *)key;

/// 获取float类型值
/// @param key 配置的key值
- (float)floatValueWithKey:(NSString *)key;

/// 获取double类型值
/// @param key 配置的key值
- (double)doubleValueWithKey:(NSString *)key;

/// 获取NSString类型值
/// @param key 配置的key值
- (nullable NSString *)stringValueWithKey:(NSString *)key;

/// 获取NSArray类型值
/// @param key 配置的key值
- (nullable NSArray *)arrayValueWithKey:(NSString *)key;

/// 获取NSDictionary类型值
/// @param key 配置的key值
- (nullable NSDictionary *)mapValueWithKey:(NSString *)key;

/// 获取NSData类型值
/// @param key 配置的key值
- (nullable NSData *)dataValueWithKey:(NSString *)key;

#pragma mark - Config Getter With DefaultValue

/// 获取配置的开关bool值
/// @param key 配置的key值
/// @param defaultValue 当配置未指定开关值，或者配置未拉到时返回的默认值
- (BOOL)isSwitchOn:(NSString *)key defaultValue:(BOOL)defaultValue;

/// 获取BOOL类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (BOOL)boolValueWithKey:(NSString *)key defaultValue:(BOOL)defaultValue;

/// 获取NSInteger类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (NSInteger)intValueWithKey:(NSString *)key defaultValue:(NSInteger)defaultValue;

/// 获取NSUInteger类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (NSUInteger)uintValueWithKey:(NSString *)key defaultValue:(NSUInteger)defaultValue;

/// 获取float类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (float)floatValueWithKey:(NSString *)key defaultValue:(float)defaultValue;

/// 获取double类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (double)doubleValueWithKey:(NSString *)key defaultValue:(double)defaultValue;

/// 获取NSString类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (NSString *)stringValueWithKey:(NSString *)key defaultValue:(NSString *)defaultValue;

/// 获取NSArray类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (NSArray *)arrayValueWithKey:(NSString *)key defaultValue:(NSArray *)defaultValue;

/// 获取NSDictionary类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值
- (NSDictionary *)mapValueWithKey:(NSString *)key defaultValue:(NSDictionary *)defaultValue;

/// 获取NSData类型值
/// @param key 配置的key值
/// @param defaultValue 默认值，如果查到key对应的配置为空，则返回默认值 
- (NSData *)dataValueWithKey:(NSString *)key defaultValue:(NSData *)defaultValue;

/// 同步从磁盘读取一个完整的配置信息
/// 因为业务反馈有在启动时需要立刻读到配置信息的需求，因此提供这个同步读取磁盘接口
/// 注意：此接口为同步读IO接口，若非必要不要使用该接口
/// @param key 配置的key值
- (nullable RDConfigInfo *)readConfigInfoWithKeyFromDisk:(NSString *)key;

/// 获取所有配置的key
- (NSArray<NSString *> *)allConfigKeys;

/// 获取所有的配置（字典），注意：
///   1. 如果本地数据已经初始化，直接返回所有配置（通常情况）
///   2. 如果本地数据尚未初始化，会同步读取本地磁盘，然后返回所有配置（最多等待3秒，若超时未读取完所有配置，则返回空）
- (NSDictionary<NSString *,RDConfigInfo *> *)allConfigInfoDictionary;

/// 配置拉取时间（单位是毫秒）,如果没有开启 RDeliverySDKSettings 的 isRecordPullTime = YES，则返回 0
/// @param key 配置 key
- (NSInteger)getLastRequestServerTimeForKey:(NSString *)key;

/// 全量配置拉取时间（单位是毫秒）,如果没有开启 RDeliverySDKSettings 的 isRecordPullTime = YES，则返回 0
- (NSInteger)getLastRequestServerTime;

#pragma mark - Settings
/// 设置自定义标签
/// @param key 标签的key值
/// @param value 标签的value值
- (void)setProfileValue:(NSString * _Nullable)value forKey:(NSString *)key;

/// 设置全局 qimei（设置后，需要自己调用 updateConfigWithCompleteHandler 触发全量拉取）
/// /// @param qimei 标签的key值
- (void)setQimei:(NSString *)qimei;

/// 重新设置定时拉取时间
/// @param duration 定时拉取时间间隔
- (void)setUpdateDuration:(NSTimeInterval)duration;

#pragma mark - Merge Config Update

/// 多个 SDK 实例聚合请求（通过减少请求次数降低成本）
/// @param sdks RDeliverySDK 示例
/// @param handler 拉到配置后的回调(会多次回调，每次返回对应 sdk 实例的结果)
- (void)batchRequestWithSDKs:(NSArray<RDeliverySDK *> *)sdks
             CompleteHandler:(void(^ _Nullable)(RDeliverySDK *sdk,
                                                NSArray<RDConfigInfo *> * _Nullable configInfoArray,
                                                NSError * _Nullable error))handler;

#pragma mark - Update Config
/// 主动更新配置
/// @param handler 拉到配置后的回调
- (void)updateConfigWithCompleteHandler:(void(^ _Nullable)(NSError * _Nullable error))handler;

/// 根据key去拉取单个配置并更新
/// @param key 配置的key
/// @param handler 拉到配置后的回调
- (void)updateConfigWithKey:(NSString *)key
            completeHandler:(void(^ _Nullable)(RDConfigInfo *configInfo, NSError * _Nullable error))handler;

/// 根据多个key去拉取多个配置并更新
/// @param keys 多个配置key的数组
/// @param handler 拉到配置后的回调
- (void)updateConfigWithKeys:(NSArray<NSString *> *)keys
             completeHandler:(void(^ _Nullable)(NSArray<RDConfigInfo *> * _Nullable configInfoArray, NSError * _Nullable error))handler;

/// 根据sceneId更新配置
/// @param sceneId 场景id
/// @param handler 拉到配置后的回调
- (void)updateConfigWithSceneId:(NSString *)sceneId
                completeHandler:(void(^ _Nullable)(NSArray<RDConfigInfo *> *configInfoArray, NSError * _Nullable error))handler;

/// 根据多个场景id请求多组远端开关配置数据
/// @param sceneIds 场景id列表
/// @param handler 拉到配置后的回调
- (void)updateConfigWithSceneIds:(NSArray<NSNumber *> *)sceneIds
                completeHandler:(void(^ _Nullable)(NSArray<RDConfigInfo *> *configInfoArray,
                                                   NSError * _Nullable error))handler;

/// 根据taskIds直接读取后台配置，配置不更新到本地
/// @param taskIds 配置任务Id
- (void)fetchConfigWithTaskIds:(NSArray<NSNumber *> *)taskIds
               completeHandler:(void(^ _Nullable)(NSArray<RDConfigInfo *> *configInfoArray, NSError * _Nullable error))handler;

/// 获取SDK配置
/// @param completion 回调
- (void)fetchSDKConfigWithCompletion:(void(^ _Nullable)(RDSDKConfigData *configData, NSError * _Nullable error))completion;

/// 扫码添加体验名单
/// @param qrcodeContent 二维码扫码结果
/// @param idType 体验名单号码类型（guid、qimei等等）
/// @param idValue 体验名单号码
/// @param completion 添加完成回调
- (void)addExpListWithQRCodeContent:(NSString *)qrcodeContent
                             idType:(NSString *)idType
                            idValue:(NSString *)idValue
                         completion:(void(^ _Nullable)(BOOL success, NSError * _Nullable error))completion;

#pragma mark - Listener
/// 为配置值变更添加一个监听者
/// @param listener 监听者
/// @param key 配置数据的key
- (void)addConfigInfoListener:(id<RDConfigInfoListener>)listener forKey:(NSString *)key;

/// 移除配置值变更监听者
/// @param listener 监听者
/// @param key 配置数据的key
- (void)removeConfigInfoListener:(id<RDConfigInfoListener>)listener forKey:(NSString *)key;

/// 为配置事件添加一个监听者
/// @param listener 监听者
- (void)addConfigEventListener:(id<RDConfigEventListener>)listener;

/// 移除配置事件监听者
/// @param listener 监听者
- (void)removeConfigEventListener:(id<RDConfigEventListener>)listener;

#pragma mark - Other
/// 切换全局用户id。不同guid的存储隔离，切换guid后，将会切换存储，读取该用户的配置
- (void)switchGuid:(NSString *)guid;

/// 切换环境。不同的环境存储隔离，切换环境后，将会切换存储，读取该环境下的配置
/// @param envId 环境ID
/// 正式环境ID：RDeliveryReleaseEnvId
/// 默认测试环境ID：RDeliveryTestEnvId
/// 其他环境ID：以Web页面上显示的环境ID为准
- (void)switchEnvironment:(NSString *)envId;

/// 获取SDK版本号
+ (NSString *)sdkVersion;

/// 是否已完成本地配置加载，如果未完成，读取配置接口将读到空，这种情况下可以监听配置初始化回调，在回调中读取配置，也可以使用 readConfigInfoWithKeyFromDisk 接口
/// 初始化SDK、切换用户id、切换环境，都会重新加载本地配置
- (BOOL)hasDataInitialized;

///  清理磁盘+ 内存数据
- (void)clearAllCache;

/// 删除内存、磁盘中单个配置
/// 重要！！！使用须知：
/// 1. 此接口仅建议在【安全模式】场景下使用，其他场景不建议主动删除，否则可能无法再次拉取本配置（未开启配置完整性校验时）。
/// 2. 调用本接口删除配置后，后台仍可能会下发本配置（开启配置完整性校验时），业务需要及时删除远端有问题的任务，避免重新下发问题任务
/// @param key 需要删除配置的key
- (void)deleteDataWithKey:(NSString *)key;

/// 获取当前配置实例命中的子任务ID标签，用于监控联动
- (NSString *)getHitSubTaskTags;

@end

NS_ASSUME_NONNULL_END
